/*
 *      Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: Chill 庄骞 (smallchill@163.com)
 */
package com.linktco.prison.impl;

import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.linktco.common.constant.Digit;
import com.linktco.common.utils.U;
import com.linktco.prison.entity.CabinetCell;
import com.linktco.prison.entity.CabinetCellUser;
import com.linktco.prison.entity.CabinetInfo;
import com.linktco.prison.service.ICabinetCellService;
import com.linktco.prison.service.ICabinetCellUserService;
import com.linktco.prison.vo.CabinetInfoVO;
import com.linktco.prison.mapper.CabinetInfoMapper;
import com.linktco.prison.service.ICabinetInfoService;
import org.springblade.core.mp.base.BaseServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import com.baomidou.mybatisplus.core.metadata.IPage;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 档案柜 服务实现类
 *
 * @author BladeX
 * @since 2024-12-23
 */
@Service
public class CabinetInfoServiceImpl extends BaseServiceImpl<CabinetInfoMapper, CabinetInfo> implements ICabinetInfoService {

    @Autowired
    private ICabinetCellService cellService;
    @Lazy
    @Autowired
    private ICabinetCellUserService cellUserService;

    @Override
    public IPage<CabinetInfoVO> selectCabinetInfoPage(IPage<CabinetInfoVO> page, CabinetInfoVO cabinetInfo) {
        return page.setRecords(baseMapper.selectCabinetInfoPage(page, cabinetInfo));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean customSave(CabinetInfo cabinet) {
        boolean save = save(cabinet);
        List<CabinetCell> cellList = getCellList(cabinet);
        return save && cellService.saveOrUpdateBatch(cellList);
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean customUpdate(CabinetInfo cabinet) {

        boolean update = updateById(cabinet);

        List<CabinetCell> cellList = getCellList(cabinet);

        List<Long> removeIds = getRemoveCellIds(cellList);
        if (!removeIds.isEmpty()) {
            cellService.removeBatchByIds(removeIds);
        }

        return update && cellService.saveOrUpdateBatch(cellList);
    }


    private List<Long> getRemoveCellIds(List<CabinetCell> cellList) {
        Long cabinetId = cellList.get(0).getCabinetId();
        List<CabinetCell> list = cellService.list(Wrappers.<CabinetCell>lambdaQuery()
                .select(CabinetCell::getId).eq(CabinetCell::getCabinetId, cabinetId));

        List<Long> dbIdList = list.stream().map(CabinetCell::getId).collect(Collectors.toList());

        List<Long> newIdList = cellList.stream().map(CabinetCell::getId).collect(Collectors.toList());

        List<Long> removeIds = new ArrayList<>();
        dbIdList.forEach(id -> {
            if (!newIdList.contains(id)) {
                removeIds.add(id);
            }
        });
        return removeIds;
    }


    private List<CabinetCell> getCellList(CabinetInfo cabinet) {
        Integer rowNum = cabinet.getRowNum();
        Integer cellNum = cabinet.getCellNum();
        List<CabinetCell> cellList = new ArrayList<>();
        for (int row = 1; row <= rowNum; row++) {
            for (int cell = 1; cell <= cellNum; cell++) {
                cellList.add(buildCell(cabinet.getId(), Digit.ONE, row, cell));
            }
        }

        for (int row = 1; row <= rowNum; row++) {
            for (int cell = 1; cell <= cellNum; cell++) {
                cellList.add(buildCell(cabinet.getId(), Digit.TWO, row, cell));
            }
        }

        return cellList;
    }


    private CabinetCell buildCell(Long cabinetId, int type, int row, int cell) {
        String cellNo = String.format("%s%s-%s", type == 1 ? "A" : "B", row, cell);
        CabinetCell dbCell = cellService.getByCellNo(cabinetId, cellNo);
        if (U.notEmpty(dbCell)) {
            return dbCell;
        }
        return CabinetCell.builder()
                .cabinetId(cabinetId)
                .type(type)
                .rows(row)
                .cellNo(cellNo)
                .build();
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean customDelete(List<Long> ids) {
        cellService.remove(Wrappers.<CabinetCell>lambdaQuery()
                .in(CabinetCell::getCabinetId,ids));
        cellUserService.remove(Wrappers.<CabinetCellUser>lambdaQuery()
                .in(CabinetCellUser::getCabinetId,ids));
        return deleteLogic(ids);
    }
}
